package com.iot08.admin.service;

import com.alibaba.fastjson.JSONObject;
import com.iot08.admin.config.mob.RedisClusterService;
import com.iot08.admin.resp.DeviceResp;
import com.iot08.admin.service.page.PageVO;
import com.iot08.admin.service.page.PageableImpl;
import com.iot08.admin.utils.ExcelUtil;
import com.iot08.admin.utils.FileUtil;
import com.iot08.admin.workTask.DevResetWorkTask;
import com.iot08.common.constant.ConstVideo;
import com.iot08.common.entity.app.*;
import com.iot08.common.entity.util.ChangeAddress;
import com.iot08.common.service.base.BaseService;
import com.iot08.common.utils.*;
import com.iot08.admin.vo.ImportDeviceReqVO;
import com.iot08.admin.vo.WatchStoreChannelVO;
import com.iot08.common.config.redis.RedisService;
import com.iot08.common.constant.Const;
import com.iot08.common.entity.admin.Channel;
import com.iot08.common.entity.admin.SysUser;
import com.iot08.common.response.Response;
import com.iot08.common.utils.DateUtil;
import com.mongodb.client.result.UpdateResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;

/**
 * @version 1.0
 * @Description: 设备相关业务
 * @time: 2020/8/27 8:52
 * @author: Rock
 */
@Slf4j
@Service
public class DeviceService extends BaseService<Device> {

    @Resource
    private ChannelService channelService;
    @Resource
    private RedisClusterService redisClusterService;
    @Resource
    private DeviceModelsService deviceModelsService;
    @Resource
    private OperationService operationService;
    @Resource
    private CanCheckPositionService canCheckPositionService;
    @Resource
    private EntryRecordService entryRecordService;
    @Resource
    private RedisService redisService;
    @Resource
    private AccountService accountService;
    @Resource
    private ResetDeviceService resetDeviceService;
    @Resource
    private NotifyService notifyService;
    @Resource
    private UserService userService;
    @Resource
    private ShiftService shiftService;
    @Resource
    private VideoModelService videoModelService;
    @Resource
    private KafkaService kafkaService;
    @Resource
    private ChannelAreaService channelAreaService;

    @Value("${device.import.path: }")
    private String importPath;
    @Value("${watch.store.channel.url: }")
    private String watchStoreChannelUrl;

    @Value("${device.tcp.url}")
    private String tcpUrl;

    public final static List<Long> excludeAgent = new ArrayList<>();

    static {
        excludeAgent.add(20000l);
        excludeAgent.add(30000l);
        excludeAgent.add(40000l);
    }

    /**
     * 设备列表 (   )
     */
    public Page<Device> list(PageVO page, String devPhone, String usrPhone, SysUser user) {
        PageableImpl pageable = new PageableImpl();
        page.setSort(Sort.by(Sort.Order.desc("ImportTime")));
        pageable.setPage(page);

        Criteria criteria = new Criteria();
        if (StringUtil.isNotBlank(page.getSearchValue())) {
            //imei也可模糊查找
            criteria.and("_id").regex(".*?" + page.getSearchValue() + ".*?", "i");
        }
        if (StringUtil.isNotBlank(devPhone)) {
            criteria.and("phone").regex(".*?" + devPhone + ".*?", "i");
        }
        if (user.getType() == Const.CHANNELUSER_TYPE) {
            if (user.getChannelArea() != null && user.getChannelArea().getChannelCode() != null) {
                criteria.and("agent").is(user.getChannelArea().getChannelCode());
            }
        }
//        if (user.getType() == Const.CHANNELUSER_TYPE) {
//            criteria.andOperator(Criteria.where("agent").in(user.getChannelAff().getChannelCodes()));
//        }

        Query query = new Query().addCriteria(criteria);
        long count = this.count(query);
        page.setTotalResult((int) count);
        List<Device> list = this.find(query.with(pageable));
        Page<Device> result = new PageImpl<Device>(list, pageable, count);
//        for (Device device : list) {
//            if (device.getAgent() != null) {
//                device.setChannel(channelService.getByChannelCode(device.getAgent()));
//            }
//            if (device.getLoc() != null && device.getLoc().containsKey("t")) {
//                if (device.getLoc().get("t") instanceof Double) {
//                    device.getLoc().put("t", ((Double) device.getLoc().get("t")).longValue());
//                }
//            }
//        }
        return result;
    }


    /**
     * 设备列表
     *
     * @param page
     * @param channelCode
     * @param user
     * @time: 2020/10/15 16:53
     * @author: Rock
     * @version 1.0
     */
    public Page<Device> list(PageVO page, Long channelCode,String modelId, SysUser user) {
        PageableImpl pageable = new PageableImpl();
        page.setSort(Sort.by(Sort.Order.desc("ImportTime")));
        pageable.setPage(page);

        Criteria criteria = new Criteria();
        if (StringUtil.isNotBlank(page.getSearchValue())) {
            criteria.and("_id").is(page.getSearchValue());
        }
        if (user.getType() == Const.CHANNELUSER_TYPE) {
            if (user.getChannelArea() != null) {
                List<String> areaIdList = channelAreaService.listIdById(user.getChannelAreaId(), true);
                criteria.and("channel_area_id").in(areaIdList);
            }
        }
        if (StringUtil.isNotBlank(channelCode)) {
            criteria.and("agent").is(channelCode);
        } else if (user.getType() == Const.CHANNELUSER_TYPE) {
            criteria.andOperator(Criteria.where("agent").in(user.getChannelAff().getChannelCodes()));
        }
        if(StringUtils.isNotEmpty(modelId)) {
            criteria.and("model_id").is(modelId);
        }

        Query query = new Query().addCriteria(criteria);
        long count = this.count(query);
        page.setTotalResult((int) count);
        List<Device> list = this.find(query.with(pageable));
        Page<Device> result = new PageImpl<Device>(list, pageable, count);
        for (Device device : list) {
            if (device.getAgent() != null) {
                device.setChannel(channelService.getByChannelCode(device.getAgent()));
            }
            if (device.getLoc() != null && device.getLoc().containsKey("t")) {
                if (device.getLoc().get("t") instanceof Double) {
                    device.getLoc().put("t", ((Double) device.getLoc().get("t")).longValue());
                }
            }
        }
        return result;
    }


    /**
     * @description
     * @author cwj
     * @param [imei, channelCode, modelId, user, response]
     * @return void
     * @date @time 2025/4/20 10:23
     **/
    public void importData(String imei, Long channelCode, String modelId, SysUser user, HttpServletResponse response) {
        Criteria criteria = new Criteria();
        if (StringUtil.isNotBlank(imei)) {
            criteria.and("_id").is(imei);
        }
        if (user.getType() == Const.CHANNELUSER_TYPE) {
            if (user.getChannelArea() != null) {
                List<String> areaIdList = channelAreaService.listIdById(user.getChannelAreaId(), true);
                criteria.and("channel_area_id").in(areaIdList);
            }
        }
        if (StringUtil.isNotBlank(channelCode)) {
            criteria.and("agent").is(channelCode);
        } else if (user.getType() == Const.CHANNELUSER_TYPE) {
            criteria.andOperator(Criteria.where("agent").in(user.getChannelAff().getChannelCodes()));
        }
        if(StringUtils.isNotEmpty(modelId)) {
            criteria.and("model_id").is(modelId);
        }
        Query query = new Query().addCriteria(criteria);
        query.with(Sort.by(Sort.Order.desc("ImportTime")));
        List<DeviceResp> list = mongoTemplate.find(query,DeviceResp.class,"device");
        try {
             exportLargeData(list,response);
        } catch (Exception e){
            log.error("设备数据导出时出现异常，异常信息为：{}",e.getMessage());
        }

    }

    /**
     * @description 
     * @author cwj
     * @param [deviceResps, response]
     * @return void
     * @date @time 2025/4/20 13:57
     **/
    public void exportLargeData(List<DeviceResp> deviceResps, HttpServletResponse response) throws Exception {
        // 创建流式工作簿，窗口大小为100（表示只保留100行在内存）
        long currentTime = System.currentTimeMillis()/1000;
        SXSSFWorkbook workbook = new SXSSFWorkbook(100);
        Sheet sheet = workbook.createSheet("设备-"+currentTime);
        Row headerRow = sheet.createRow(0);
        headerRow.createCell(0).setCellValue("imei");
        headerRow.createCell(1).setCellValue("设备型号");
        headerRow.createCell(2).setCellValue("导入时间");

        for (int i = 0; i < deviceResps.size(); i++) {
            DeviceResp deviceResp = deviceResps.get(i);
            Row row = sheet.createRow(i + 1);
            row.createCell(0).setCellValue(deviceResp.getImei());
            row.createCell(1).setCellValue(deviceResp.getModel());
            row.createCell(2).setCellValue(ObjectUtils.isEmpty(deviceResp.getImportTime()) ?"":DateUtil.dateToStr(deviceResp.getImportTime(),DateUtil.FORMAT_1));
        }
        // 设置导出
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setHeader("Content-Disposition", "attachment;filename=" +
                URLEncoder.encode("设备-"+currentTime+".xlsx", "UTF-8"));
        workbook.write(response.getOutputStream());
        // 清理临时文件
        workbook.dispose();
        workbook.close();
    }

    /**
     * 设备录入
     *
     * @time: 2020/8/28 17:15
     * @author: Rock
     * @version 1.0
     */
    public Response<Object> importDevice(ImportDeviceReqVO vo, SysUser user, String ip,
                                         MultipartFile file, boolean isJFvideolimit553) throws Exception {
        //把文件上传到服务器
        String filename = DateUtil.dateToStr(new Date(), DateUtil.FORMAT_3) + "-" + file.getOriginalFilename();
        FileUtil.upload(file, importPath, filename);
        Workbook wb = WorkbookFactory.create(new ByteArrayInputStream(file.getBytes()));
        if (wb != null && wb.getSheetAt(0) != null) {
            Sheet sheet = wb.getSheetAt(0);
            Set<String> set = ExcelUtil.getImei(sheet);
            if (set.size() <= 0) {
                return Response.failedResponse("excel表内无数据");
            }
            int countRow = set.size();
            if (countRow > 30000) {
                return Response.failedResponse("录入失败，设备号文件不能超过3W个号码");
            }
            List<String> list = new ArrayList<>();
            List<String> noRepeatList = new ArrayList<>();
            //重复号码
            List<String> repeatList = new ArrayList<>();
            for (String imei : set) {
                if (StringUtil.isBlank(imei)) {
                    continue;
                }
                if (!RegexUtil.validateDeviceId(imei.trim())) {
                    return Response.failedResponse("存在非法号码：" + imei.trim());
                }
                if (countByImei(imei) != 0) {
                    repeatList.add(imei.trim());
//                    return Response.failedResponse("存在重复号码：" + imei.trim());
                }else {
                    noRepeatList.add(imei.trim());
                }
                list.add(imei.trim());
            }
            if (list.size() <= 0) {
                return Response.failedResponse("excel表内无数据");
            }
            if (repeatList.size() > 0) {
                if(noRepeatList.size() > 0) {
                    return Response.failedResponse("存在重复号码：" + repeatList+"\r\n不重复的号码："+noRepeatList);
                } else {
                    return Response.failedResponse("存在重复号码：" + repeatList);
                }
            }

            Channel channel = channelService.findById(vo.getChannelId());
            String msg = importHandle(list, vo, channel, user, filename, ip, null);
            return Response.successResponse(msg);
        }
        return Response.failedResponse("上传文件异常");
    }

    /**
     * 设备导入处理
     *
     * @param list, models, channel, ifHaveProductionBatch, user, filename]
     * @time: 2020/8/28 17:34
     * @author: Rock
     * @version 1.0
     */
    private String importHandle(List<String> list, ImportDeviceReqVO vo, Channel channel,
                                SysUser user, String filename, String ip, String imei) {
        String nowTime = DateUtil.dateToStr(new Date(), DateUtil.FORMAT_2); //生产批次
        String devModelId = vo.getDevModelId();
        DeviceModels devModel = deviceModelsService.findById(devModelId);
        boolean isJFvideolimit553 = false;
        VideoModel videoModel = null;
        if(devModel.getVideo_modelid() != null){
            //选择了视频规则的都是有553 规则的
            isJFvideolimit553 = true;
            videoModel = videoModelService.getById(devModel.getVideo_modelid());
        }
        int successNum = 0;
        for (String s : list) {
            Device d = new Device();
            d.setId(s);
            d.setManualImport(1);
            d.setVendor(20000);
            d.setAgent(channel.getChannelCode());
            d.setModules(devModel.getModules());
            d.setModelId(devModelId); //设置设备类型
            d.setModel(devModel.getModel());//设置设备类型名称
            d.setImportTime(new Date());
            d.setCancelVideoAutoHangUp(0);
            d.setCanCheckPosition(vo.getCanCheckPosition());
            d.setVideoLimitstatus(0);
            d.setVideoModelId(devModel.getVideo_modelid());
//            if (Const.INT_1.equals(devModel.getIfHaveProductionBatch())) {
//                d.setProductionBatch(nowTime);
//            }
            //设置是否为新版微聊协议
            d.setIsNewWechatProtocol(vo.getIsNewWechatProtocol());
            //必须生成
            d.setProductionBatch(nowTime);
            //设置设备是否支持RTOS
            if(vo.getIsRtosModule() == 0){
                d.setPlatform("Android_M");
            } else {
                d.setPlatform("ASR");
            }
            if (Const.INT_1.equals(devModel.getIsWatchCustomFunction())) {
                d.setIsWatchCustomFunction(1);
            } else {
                d.setPpmfmodules(devModel.getPpmfmodules());
                d.setTelecom(1);
                d.setNavigationmodules(devModel.getNavigationmodules());
                d.setDataFlow(devModel.getDataFlow());
                d.setCostFlow(devModel.getCostFlow());
                d.setDialSwitch(devModel.getOpdialswitch());
            }
//            if (StringUtil.isNotBlank(vo.getWatchStoreChannelId())) {
//                d.setWatchStoreChannelId(vo.getWatchStoreChannelId());
//                d.setWatchStoreChannelName(vo.getWatchStoreChannelName());
//            }
//            if (StringUtil.isNotBlank(vo.getDmpAccountId())) {
//                d.setDmpAccountId(vo.getDmpAccountId());
//            }
            // 前面已经检查过, 没有重复导入的 IMEI
            mongoTemplate.save(d);
            successNum++;
            if (StringUtil.isBlank(redisClusterService.hget(d.getId(), "v"))) {
                redisClusterService.hset(d.getId(), "v", "20000");
            }
            //10位 短号
            if(devModel.getIsDevIMEIShort() == 1){
//                # 截取 4~14位 的短标识
//                shortId = imei[4:14]
//                r.hset(imei, 'shortId', shortId)
//                r.set("SHORT:"+shortId, imei)

                String shortId = s.substring(4, 14);
                redisClusterService.hset(s, "shortId", shortId);
                //这个会在 TCP 程序中 用上
                redisClusterService.set("SHORT:"+shortId, s);
                log.info("{} 的 10 位短号导入 {}", s, shortId);
            }

            if (Const.INT_1.equals(vo.getCanCheckPosition())) {
                //如果是 可以查看位置的表, 插入一条数据到can_check_position表中
                canCheckPositionService.save(s, channel.getChannelCode() + "", 1, null);
            }

        }
        if (successNum > 0 && Const.INT_1.equals(vo.getIfHaveProductionBatch())) {
            //添加导入记录
            entryRecordService.save(nowTime, channel.getChannelCode() + "", channel.getName(), successNum,
                    null, user.getAccount());
        }
        //更新渠道导入设备的数量
//        channelService.updateNum(channel.getChannelCode(), successNum); // 定时自动更新
//        videoModelService.updateImportNum(vo.getVideoModelId(), successNum); // 定时自动更新
//        deviceModelsService.updateNum(devModel, successNum); // 定时自动更新

        Integer flag = 1;
        //添加操作记录
        String describe = String.format("成功录入%s个设备号； 选择渠道商为：%s； ", successNum, channel.getName());
        if (vo.getCanCheckPosition() != null && flag.equals(vo.getCanCheckPosition())) {
            describe += " 渠道商查看设备位置; ";
        }
        if (flag.equals(vo.getIfHaveProductionBatch())) {
            describe += " 生产批次：自动生成;";
        }
        describe += "<br/>视频通话：";
        if (devModel.getModules() != null) {
            //视频通话配置描述
            if (devModel.getModules().contains(ConstVideo.V0SW)) {
                describe += "支持声网、";
            }
            if (devModel.getModules().contains(ConstVideo.V0JF)) {
                describe += "支持juphoon、";
            }
            if (devModel.getModules().contains(ConstVideo.V0VM)) {
                describe += "支持视通、";
            }
        }
//        if (flag.equals(vo.getJuphoonPermanent())) {
//            if (vo.getModules().contains(ConstVideo.V0JF)) {
//                describe += "JF视频免费、";
//            }
//            if (vo.getModules().contains(ConstVideo.V0VM)) {
//                describe += "VM视频免费、";
//            }
//        }
        if (!isJFvideolimit553) {
            if (devModel.getModules().contains(ConstVideo.V0JF)) {
                describe += "JF视频通话限制（553机制)、";
            }
            if (devModel.getModules().contains(ConstVideo.V0VM)) {
                describe += "VM视频通话限制（553机制)、";
            }
        }
//        if (flag.equals(vo.getVideoLimitStatus())) {
//            describe += "(声网)限制通话时长（5分钟）、";
//        }
        if (StringUtil.isNotBlank(devModel.getVideo_modelid())) {
            if (videoModel != null) {
                describe += "选择视频限制类型: " + videoModel.getName();
            }
        }

        if (devModel.getOpDicpenCloudType() > -1) {
            //云词本功能 0:本地词本 1:移动词本 2: 电信词本
            describe += "；<br/>云词本类型:";
            switch (devModel.getOpDicpenCloudType()) {
                case 0:
                    describe += "本地词本";
                    break;
                case 1:
                    describe += "移动词本";
                    break;
                case 2:
                    describe += "电信词本";
                    break;
            }
        }

        if (Const.INT_1.equals(devModel.getIsDevIMEIShort())) {
            //是否支持 10位短号 isDevIMEIShort
            describe += "；<br/>是否支持10位短号：支持";
        }

        if (Const.INT_1.equals(devModel.getIsWatchCustomFunction())) {
            describe += "；<br/>功能配置：选择设备自动配置功能";
        } else {
            describe += "；<br/> 功能配置：";
            if (devModel.getModules() != null) {
                if (devModel.getModules().contains("L0")) {
                    describe += "基站定位功能、";
                }
                if (devModel.getModules().contains("L1")) {
                    describe += "基站+WiFi定位功能、";
                }
                if (devModel.getModules().contains("L2")) {
                    describe += "基站+GPS定位功能、";
                }
                if (devModel.getModules().contains("L3")) {
                    describe += "基站+WiFi+GPS定位功能、";
                }
                if (devModel.getModules().contains("P0")) {
                    describe += "拍照功能、";
                }
                if (devModel.getModules().contains("S0")) {
                    describe += "计步功能、";
                }
            }
            if (flag.equals(devModel.getPpmfmodules())) {
                describe += "碰碰交友、";
            }
//            if (flag.equals(devModel.getTelecom())) {
//                describe += "电信版本、";
//            }
            if (flag.equals(devModel.getDataFlow())) {
                describe += "设备流量监控、";
            }
            if (flag.equals(devModel.getCostFlow())) {
                describe += "设备查询话费流量功能、";
            }
            if (flag.equals(devModel.getOpdialswitch())) {
                describe += "拨号盘控制";
            }
//            if (StringUtil.isNotBlank(vo.getWatchStoreChannelId())) {
//                describe += "选择设备商店渠道: " + vo.getWatchStoreChannelName();
//            }
        }

        if (StringUtil.isBlank(imei)) {
            //添加日志
            operationService.add(user, ip, Const.OPERATION_ADD, "设备录入", channel.getName(),
                    "批量录入", describe, null, filename, imei);
        } else {
            //添加日志
            operationService.add(user, ip, Const.OPERATION_ADD, "设备录入", channel.getName(),
                    "单个录入", describe, null, filename, imei);
        }
        return describe;
    }

    /**
     * 单个添加
     *
     * @time: 2020/8/28 18:09
     * @author: Rock
     * @version 1.0
     */
    public Response<Object> add(ImportDeviceReqVO vo, SysUser user, String ip, boolean isJFvideolimit553) {
        if (countByImei(vo.getImei()) > 0) {
            return Response.failedResponse("录入失败，设备号已存在");
        } else if (!RegexUtil.validateDeviceId(vo.getImei())) {
            return Response.failedResponse("录入失败，设备号不合法");
        } else {
            Channel channel = channelService.findById(vo.getChannelId());
            List<String> list = new ArrayList<>();
            list.add(vo.getImei());
            String msg = importHandle(list, vo, channel, user, null, ip, vo.getImei());
            return Response.successResponse(msg);
        }
    }

    /**
     * @param user, imei
     * @time: 2020/8/31 17:12
     * @author: Rock
     * @version 1.0
     */
    public Response<Object> searchAcviteByImei(SysUser user, String imei) throws Exception {
        if (user.getType() == Const.CHANNELUSER_TYPE) {
            return Response.failedResponse("无权限查询");
        }
        Device d = findById(imei);
        if (d == null) {
            return Response.failedResponse("设备号不存在");
        }
        List<String> list = new ArrayList<>();
        list.add("设备号: " + imei);
        //最后一次激活时间
        String lastActiveTime = mapStampHandle(d.getChatGroupMap());
        if (lastActiveTime != "") {
            list.add("激活时间: " + lastActiveTime);
        } else {
            list.add("激活时间: 暂无");
        }
        String lastTimeActiveTime = "";
        String resetTime = "";
        String resetOperator = "";
        //上一次激活时间
        ResetDevice rd = resetDeviceService.getById(imei);
        if (rd != null) {
            lastTimeActiveTime = mapStampHandle(rd.getG());
            resetOperator = rd.getResetOperator();
            if (StringUtil.isNotBlank(rd.getResetTime())) {
                resetTime = DateUtil.dateToStr(rd.getResetTime(), DateUtil.FORMAT_1);
            }
        }
        if (StringUtil.isNotBlank(lastTimeActiveTime)) {
            list.add("上一次激活时间: " + lastTimeActiveTime);
        } else {
            list.add("上一次激活时间: 暂无");
        }
        if (StringUtil.isNotBlank(resetTime)) {
            list.add("上一次时间: " + resetTime);
        } else {
            list.add("上一次解绑时间: 暂无");
        }
        if (StringUtil.isNotBlank(resetOperator)) {
            list.add("解绑方式: " + resetOperator);
        } else {
            list.add("解绑方式: 暂无");
        }
        return Response.successResponse(list);
    }

    /**
     * @param g
     * @time: 2020/10/21 11:35
     * @author: Rock
     * @version 1.0
     */
    private String mapStampHandle(Map<String, Map<String, Object>> g) {
        if (g != null) {
            for (Map.Entry<String, Map<String, Object>> entry : g.entrySet()) {
                if (entry.getValue().get("t") instanceof Double) {
                    return DateUtil.stampToDateStr(((Double) entry.getValue().get("t")).longValue() * 1000, DateUtil.FORMAT_1);
                }
            }
        }
        return "";
    }

    /**
     * @time: 2020/8/31 16:35
     * @author: Rock
     * @version 1.0
     */
    public Response<Object> searchActiveByExcel(SysUser user, MultipartFile file) throws Exception {
        if (user.getType() == Const.CHANNELUSER_TYPE) {
            return Response.failedResponse("无权限查询");
        }
        String fileName = "";
        Workbook wb = WorkbookFactory.create(new ByteArrayInputStream(file.getBytes()));
        if (wb != null && wb.getSheetAt(0) != null) {
            Sheet sheet = wb.getSheetAt(0);
            int countRow = sheet.getPhysicalNumberOfRows();
            if (countRow > 1000) {
                return Response.failedResponse("文件不能超过1000个号码");
            }
            Set<String> set = ExcelUtil.getImei(sheet);
            if (set.size() <= 0) {
                return Response.failedResponse("excel表内无数据");
            }
            Query query = new Query();
            Criteria criteria = Criteria.where("_id").in(set);
            if (user.getType() == Const.CHANNELUSER_TYPE) {
                criteria.orOperator(Criteria.where("agent").in(user.getChannelAff().getChannelCodes()),
                        Criteria.where("agent").exists(false));
            }
            query.addCriteria(criteria);
            query.fields().include("_id").include("g");
            List<Device> list = mongoTemplate.find(query, Device.class);
            Row row = null;
            Cell cell = null;
            if (list.size() > 0) {
                //查找到的
                Workbook foundExcel = new XSSFWorkbook();
                Sheet foundSheet = foundExcel.createSheet();
                row = foundSheet.createRow(0);
                cell = row.createCell(0);
                ExcelUtil.setCellValue(cell, "设备号imei");
                cell = row.createCell(1);
                ExcelUtil.setCellValue(cell, "激活时间");
                cell = row.createCell(2);
                ExcelUtil.setCellValue(cell, "上一次解绑时间");
                cell = row.createCell(3);
                ExcelUtil.setCellValue(cell, "上一次激活时间");
                cell = row.createCell(4);
                ExcelUtil.setCellValue(cell, "解绑方式");
                for (int i = 0; i < list.size(); i++) {
                    row = foundSheet.createRow(i + 1);
                    cell = row.createCell(0);
                    ExcelUtil.setCellValue(cell, list.get(i).getId());
                    cell = row.createCell(1);
                    ExcelUtil.setCellValue(cell, mapStampHandle(list.get(i).getChatGroupMap()));
                    ResetDevice rd = resetDeviceService.getById(list.get(i).getId());
                    if (rd != null) {
                        cell = row.createCell(2);
                        ExcelUtil.setCellValue(cell, mapStampHandle(rd.getG()));
                        cell = row.createCell(3);
                        ExcelUtil.setCellValue(cell, DateUtil.dateToStr(rd.getResetTime(), DateUtil.FORMAT_1));
                        cell = row.createCell(4);
                        ExcelUtil.setCellValue(cell, rd.getResetOperator());
                    }
                }
                fileName = DateUtil.dateToStr(new Date(), DateUtil.FORMAT_5) + "_查询激活状况" + list.size() + "pcs.xlsx";
                FileOutputStream foundFile = new FileOutputStream(importPath + File.separator + fileName);
                foundExcel.write(foundFile);
                foundFile.close();
            }
            Map<String, Object> map = new HashMap<>();
            String msg = "";
            if (list.size() == 0) {
                msg = "查询失败，号码都不存在";
            } else {
                msg = String.format("成功查询到%s个设备号，请下载文件查看，", list.size());
            }
            map.put("msg", msg);
            map.put("fileName", fileName);
            return Response.successResponse(map);
        }
        return Response.failedResponse("上传文件异常");
    }

    /**
     * @time: 2020/8/31 16:35
     * @author: Rock
     * @version 1.0
     */
    public Response<Object> searchByExcel(SysUser user, MultipartFile file) throws Exception {
        String foundExcelUrl = "";
        //String foundNotJurisdictionExcelUrl = "";
        //String notFoundExcelUrl = "";
        Workbook wb = WorkbookFactory.create(new ByteArrayInputStream(file.getBytes()));
        if (wb != null && wb.getSheetAt(0) != null) {
            Sheet sheet = wb.getSheetAt(0);
            int countRow = sheet.getPhysicalNumberOfRows();
            if (countRow > 20000) {
                return Response.failedResponse("文件不能超过2W个号码");
            }
            Set<String> set = ExcelUtil.getImei(sheet);
            if (set.size() <= 0) {
                return Response.failedResponse("excel表内无数据");
            }
            List<Device> found = new ArrayList<>();
            List<Device> foundNotJurisdiction = new ArrayList<>();
            Query query = new Query(Criteria.where("_id").in(set));
            query.fields().include("_id").include("agent").include("channel_area_id");
            List<Device> list = mongoTemplate.find(query, Device.class);
            if (list != null && list.size() > 0) {
                if (user.getType() == Const.CHANNELUSER_TYPE) {
                    if (user.getChannelArea() != null) {
                        List<String> areaIdList = channelAreaService.listIdById(user.getChannelAreaId(), true);
                        for (Device d : list) {
                            if (d.getChannelAreaId() != null && areaIdList.contains(d.getChannelAreaId())) {
                                found.add(d);
                            } else {
                                foundNotJurisdiction.add(d);
                            }
                        }
                    } else {
                        for (Device d : list) {
                            if (StringUtil.isBlank(d.getAgent()) ||
                                    user.getChannelAff().getChannelCodes().contains(d.getAgent())
                                    || excludeAgent.contains(d.getAgent())) {
                                found.add(d);
                            } else {
                                foundNotJurisdiction.add(d);
                            }
                        }
                    }
                } else {
                    found.addAll(list);
                }
            }
            Row row = null;
            Cell cell = null;
            if (found.size() > 0) {
                //查找到的
                Workbook foundExcel = new XSSFWorkbook();
                Sheet foundSheet = foundExcel.createSheet();
                for (int i = 0; i < found.size(); i++) {
                    row = foundSheet.createRow(i);
                    cell = row.createCell(0);
                    ExcelUtil.setCellValue(cell, found.get(i).getId());
                    set.remove(found.get(i).getId());
                }
                foundExcelUrl = importPath + File.separator + user.getId() + "-found.xlsx";
                FileOutputStream foundFile = new FileOutputStream(foundExcelUrl);
                foundExcel.write(foundFile);
                foundFile.close();
            }
            /*if(foundNotJurisdiction.size() > 0){
                //查找到但没有权限访问的
                Workbook foundExcel = new XSSFWorkbook();
                Sheet foundSheet = foundExcel.createSheet();
                for (int i=0; i < foundNotJurisdiction.size(); i++){
                    row = foundSheet.createRow(i);
                    cell = row.createCell(0);
                    ExcelUtil.setCellValue(cell, foundNotJurisdiction.get(i).getId());
                    set.remove(foundNotJurisdiction.get(i).getId());
                }
                foundNotJurisdictionExcelUrl = importPath + File.separator + user.getId() + "-found_not_jurisdiction.xlsx";
                FileOutputStream foundNotJurisdictionFile = new FileOutputStream(foundNotJurisdictionExcelUrl);
                foundExcel.write(foundNotJurisdictionFile);
                foundNotJurisdictionFile.close();
            }*/
            /*if(set.size() > 0){
                //没有查找到的
                Workbook notFoundExcel = new XSSFWorkbook();
                Sheet notFoundSheet = notFoundExcel.createSheet();
                int index = 0;
                for (String notFoundId : set) {
                    row = notFoundSheet.createRow(index);
                    cell = row.createCell(0);
                    ExcelUtil.setCellValue(cell, notFoundId);
                    index++;
                }
                notFoundExcelUrl = importPath + File.separator + user.getId() + "-not_found.xlsx";
                FileOutputStream notFoundFile = new FileOutputStream(notFoundExcelUrl);
                notFoundExcel.write(notFoundFile);
                notFoundFile.close();
            }*/
            Map<String, Object> map = new HashMap<>();
            String msg = "";
            if (list.size() == 0) {
                msg = "设备号都未录入";
            } else {
                msg = String.format("找到%s个设备号，", list.size());
                if (foundNotJurisdiction.size() > 0) {
                    msg += String.format("其中有权限访问%s个，无权限访问%s个，", found.size(), foundNotJurisdiction.size());
                }
                if (found.size() > 0) {
                    msg += "详细下载文件查看";
                }
            }
            map.put("msg", msg);
            map.put("foundExcelUrl", foundExcelUrl);
            //map.put("foundNotJurisdictionExcelUrl", foundNotJurisdictionExcelUrl);
            //map.put("notFoundExcelUrl", notFoundExcelUrl);
            return Response.successResponse(map);
        }
        return Response.failedResponse("上传文件异常");
    }

    /**
     * 解绑
     *
     * @time: 2020/8/31 18:01
     * @author: Rock
     * @version 1.0
     */
    public Response<Object> unbindByImei(SysUser user, String imei, String ip, boolean isLossDevUnbindOption) throws Exception {
        //解绑数量检查
        String nowDateStr = DateUtil.dateToStr(new Date(), DateUtil.FORMAT_4);
        SysUser su = userService.findById(user.getId());
        if (su.getType() == Const.CHANNELUSER_TYPE) {
            if (su.getUnbindNum() < 0 || (nowDateStr.equals(su.getUnbindDate()) && su.getTodayUnbindNum() != null
                    && su.getTodayUnbindNum() >= su.getUnbindNum())) {
                return Response.failedResponse(String.format("今天已解绑达到上限%s个,请明天再执行", su.getUnbindNum()));
            }
        }
        Device device = this.findById(imei);
        if (device != null) {
            if (user.getType() == Const.CHANNELUSER_TYPE) {
                if (user.getChannelArea() != null) {
                    List<String> areaIdList = channelAreaService.listIdById(user.getChannelAreaId(), true);
                    if (user.getChannelAreaId() == null || !areaIdList.contains(device.getChannelAreaId())) {
                        return Response.failedResponse("解绑失败，请联系我司客服人员处理");
                    }
                } else {
                    if (StringUtil.isNotBlank(device.getAgent())
                            && !user.getChannelAff().getChannelCodes().contains(device.getAgent())
                            && !excludeAgent.contains(device.getAgent())) {
                        return Response.failedResponse("解绑失败，请联系我司客服人员处理!");
                    }
                }
            }
            //多余操作
//            if (StringUtil.isNotBlank(device.getWatchStoreChannelId())) {
//                String url = watchStoreChannelUrl + "/getway/regulatory/restoreInitialState?authKey=%s&timestamp=%s&imeis=%s";
//                long timestamp = System.currentTimeMillis();
//                String authKey = DigestUtils.md5Hex(Const.MD5_KEY + timestamp).toUpperCase();
//                String jsonImeiStr = JSON.toJSONString(imei);
//                String res = HttpReq.sendGet(String.format(url, authKey, timestamp, jsonImeiStr), null);
//                JSONObject json = JSON.parseObject(res);
//                if (json != null && new Integer(200).equals(json.getInteger("code"))) {
//                    log.info("恢复应用监管原始状态 成功,http的参数:timestamp={}, authKey={}, jsonImeiStr={}; response.json()={}", timestamp, authKey, jsonImeiStr, json);
//                } else {
//                    log.info("恢复应用监管原始状态 失败,http的参数:timestamp={}, authKey={}, jsonImeiStr={}; response.json()={}", timestamp, authKey, jsonImeiStr, json);
//                }
//            }
            //解绑通知(发送请求解绑)
            JSONObject res = notifyService.deviceReset(imei, "WEB:" + user.getId(), isLossDevUnbindOption, user);
            if(res != null){
                if(res.getInteger("code") == 400){
                    return Response.failedResponse("imei:"+imei+" 解绑失败，请检查 或 联系我司客服人员处理!");
                }
                if(res.getInteger("code") == 6001){
                    //设备挂失中
                    String errMsg = String.format("imei: %s %s 解绑失败，请检查 或 联系我司客服人员处理!",imei ,res.getString("msg"));
                    return Response.failedResponse(errMsg);
                }
            }else{
                return Response.failedResponse("解绑失败，请联系我司客服人员处理!");
            }
//            kafkaService.emitDeviceDemand(imei, 44);
            //notifyService.emitDeviceDemand(imei, 44);
            //添加操作记录
            operationService.add(user, ip, Const.OPERATION_DELETE, "设备解绑", null, "单个解绑", "成功解绑1个", null, null, imei);
            if (su.getType() == Const.CHANNELUSER_TYPE) {
                //更新解绑数量
                userService.updateTodayUnbindNum(user.getId(), 1);
            }
            return Response.successResponse("imei:"+imei+" 解绑成功");
        }
        return Response.failedResponse("设备号不存在");
    }

    /**
     * 解绑设备多个
     *
     * @time: 2020/9/5 9:00
     * @author: Rock
     * @version 1.0
     */
    public Response<Object> unbindByExcel(SysUser user, MultipartFile file, String ip) throws Exception {
        String notUnbindExcelUrl = "";
        String msg = "";
        //把文件上传到服务器
        String filename = DateUtil.dateToStr(new Date(), DateUtil.FORMAT_3) + "-" + file.getOriginalFilename();
        FileUtil.upload(file, importPath, filename);
        Workbook wb = WorkbookFactory.create(new ByteArrayInputStream(file.getBytes()));
        if (wb != null && wb.getSheetAt(0) != null) {
            Sheet sheet = wb.getSheetAt(0);
            Set<String> set = ExcelUtil.getImei(sheet);
            if (set.size() <= 0) {
                return Response.failedResponse("excel表内无数据");
            }
            //解绑数量检查
            String nowDateStr = DateUtil.dateToStr(new Date(), DateUtil.FORMAT_4);
            SysUser su = userService.findById(user.getId());
            if (su.getType() == Const.CHANNELUSER_TYPE) {
                if (su.getUnbindNum() <= 0) {
                    return Response.failedResponse("当前账号无解绑权限");
                } else if (set.size() > su.getUnbindNum()) {
                    return Response.failedResponse(String.format("文件不能超过%s个号码", su.getUnbindNum()));
                } else if (nowDateStr.equals(su.getUnbindDate()) && su.getTodayUnbindNum() != null
                        && su.getTodayUnbindNum() + set.size() > su.getUnbindNum()) {
                    return Response.failedResponse(String.format("今天已解绑超上限%s个,请明天再执行(文件号码为%s个，今天剩余解绑次数为%s个)",
                            su.getUnbindNum(), set.size(), su.getUnbindNum() - su.getTodayUnbindNum()));
                }
            } else {
                if (set.size() > 10000) {
                    return Response.failedResponse("文件不能超过10000个号码");
                }
            }

            //先生成个任务ID 异步返回结果给前端,前端可使用 任务ID 进行进度的查询
            String workId = UUIDGenerator.generate();

            //新建一个线程执行耗时操作
            DevResetWorkTask workTask = new DevResetWorkTask(
                    operationService,
                    notifyService,
                    userService,
                    channelAreaService,
                    importPath,
                    set,
                    excludeAgent,
                    mongoTemplate,
                    su,
                    ip,
                    filename,
                    redisService,
                    workId
            );
            workTask.start();
            Map<String, Object> map = new HashMap<>();
            map.put("workId", workId);
            map.put("showMsg", "正在执行解绑,请不要关闭页面,如关闭页面, 执行操作成功与否需要查询 解绑日志记录 得知");
            return Response.successResponse(map);

//            Query query = new Query();
//            Criteria criteria = Criteria.where("_id").in(set);
//            if (user.getType() == Const.CHANNELUSER_TYPE) {
//                if (user.getChannelArea() != null) {
//                    List<String> areaIdList = channelAreaService.listIdById(user.getChannelAreaId(), true);
//                    criteria.and("channel_area_id").in(areaIdList);
//                }
//                //渠道账号，获取所拥有的渠道
//                criteria.orOperator(Criteria.where("agent").in(user.getChannelAff().getChannelCodes()),
//                        Criteria.where("agent").in(excludeAgent),
//                        Criteria.where("agent").exists(false));
//            }
//
//            query.addCriteria(criteria);
//            query.fields().include("_id");
//            List<String> imeiList = new ArrayList<>();
//            List<Device> list = mongoTemplate.find(query, Device.class);
//            Row row = null;
//            Cell cell = null;
//            if (list.size() > 0) {
//                //可解绑到的
//                for (int i = 0; i < list.size(); i++) {
//                    if (list.get(i) == null) {
//                        continue;
//                    }
//                    //解绑通知
//                    Device temDev = list.get(i);
//                    Boolean res = notifyService.deviceReset(temDev.getId(), "WEB:" + user.getId());
//                    if(res){
//                        imeiList.add(list.get(i).getId());
//                        set.remove(list.get(i).getId());
//                    }
//
//                }
//            }
//            if (set.size() > 0) {
//                //没有解绑的
//                Workbook notDelExcel = new XSSFWorkbook();
//                Sheet notFoundSheet = notDelExcel.createSheet();
//                int index = 0;
//                for (String notDelId : set) {
//                    row = notFoundSheet.createRow(index);
//                    cell = row.createCell(0);
//                    ExcelUtil.setCellValue(cell, notDelId);
//                    index++;
//                }
//                notUnbindExcelUrl = importPath + File.separator + user.getId() + "-not_unbind.xlsx";
//                FileOutputStream notUnbindFile = new FileOutputStream(notUnbindExcelUrl);
//                notDelExcel.write(notUnbindFile);
//                notUnbindFile.close();
//                msg = String.format("成功解绑%s个设备号，不成功%s个，可能imei不属于您或错误, 解绑失败号码请下载文件查看", list.size(), set.size());
//            } else {
//                msg = String.format("成功解绑%s个设备号", list.size());
//            }
//            Map<String, Object> map = new HashMap<>();
//            map.put("msg", msg);
//            map.put("notUnbindExcelUrl", notUnbindExcelUrl);
//
//            if (list.size() > 0) {
//                if (su.getType() == Const.CHANNELUSER_TYPE) {
//                    //更新解绑数量
//                    userService.updateTodayUnbindNum(user.getId(), list.size());
//                }
//                String desStr = String.format("成功解绑%s个, 不成功%s个 可能imei不属于您或错误", list.size(), set.size());
//                if(StringUtils.isNotEmpty(notUnbindExcelUrl)){
//                    String downAHTMl = "<a href=\"device/downloadExcel?type=2\" class=\"\">下载文件</a>";
//                    desStr = String.format("成功解绑%s个, 不成功%s个, 可能imei不属于您或错误,不成功的下载文件(只会保留最新的不成功文件):%s", list.size(), set.size(), downAHTMl);
//                }
//
//                //添加操作记录
//                operationService.add(user, ip, Const.OPERATION_DELETE, "设备解绑",
//                        null, "多个解绑", desStr, null, filename, null);
//            }

        }
        return Response.failedResponse("上传文件异常");
    }

    /**
     * 单个删除
     *
     * @time: 2020/9/1 12:05
     * @author: Rock
     * @version 1.0
     */
    public Response<Object> delByImei(SysUser user, String imei, String ip) {
        if (user.getType() == Const.CHANNELUSER_TYPE) {
            //渠道账号无权限
            return Response.failedResponse("无权限");
        }
        Device device = findById(imei);
        if (device != null) {
            //刪除
            delHandle(device, "WEB:"+user.getId(), user);
            //添加操作记录
            operationService.add(user, ip, Const.OPERATION_REMOVE, "设备删除",
                    null, "单个刪除", "成功删除1个", null, null, imei);
        }
        return Response.successResponse(device);
    }

    /**
     * 多个删除
     *
     * @time: 2020/9/1 12:07
     * @author: Rock
     * @version 1.0
     */
    public Response<Object> delByExcel(SysUser user, MultipartFile file, String ip) throws Exception {
        String notDelExcelUrl = "";
        String msg = "";
        //把文件上传到服务器
        String filename = DateUtil.dateToStr(new Date(), DateUtil.FORMAT_3) + "-" + file.getOriginalFilename();
        FileUtil.upload(file, importPath, filename);
        Workbook wb = WorkbookFactory.create(new ByteArrayInputStream(file.getBytes()));
        if (wb != null && wb.getSheetAt(0) != null) {
            Sheet sheet = wb.getSheetAt(0);
            Set<String> set = ExcelUtil.getImei(sheet);
            if (set.size() <= 0) {
                return Response.failedResponse("excel表内无数据");
            }
            if (set.size() > 10000) {
                return Response.failedResponse("文件不能超过10000个号码");
            }
            Query query = new Query();
            Criteria criteria = Criteria.where("_id").in(set);
            if (user.getType() != 0) {
                //渠道账号，无权访问删除
                return Response.failedResponse("无权访问");
            }
            query.addCriteria(criteria);
            query.fields().include("_id").include("agent").include("model_id");
            List<Device> list = mongoTemplate.find(query, Device.class);
            Row row = null;
            Cell cell = null;
            if (list.size() > 0) {
                //可删除到的
                for (int i = 0; i < list.size(); i++) {
                    if (list.get(i) == null) {
                        continue;
                    }
                    delHandle(list.get(i), "WEB:"+user.getId(), user);
                    set.remove(list.get(i).getId());
                }
            }
            if (set.size() > 0) {
                //没有删除的
                Workbook notDelExcel = new XSSFWorkbook();
                Sheet notFoundSheet = notDelExcel.createSheet();
                int index = 0;
                for (String notDelId : set) {
                    row = notFoundSheet.createRow(index);
                    cell = row.createCell(0);
                    ExcelUtil.setCellValue(cell, notDelId);
                    index++;
                }
                notDelExcelUrl = importPath + File.separator + user.getId() + "-not_del.xlsx";
                FileOutputStream notDelFile = new FileOutputStream(notDelExcelUrl);
                notDelExcel.write(notDelFile);
                notDelFile.close();
                msg = String.format("成功删除%s个设备号，不成功%s个，不成功号码请下载文件查看", list.size(), set.size());
            } else {
                msg = String.format("成功删除%s个设备号", list.size());
            }
            Map<String, Object> map = new HashMap<>();
            map.put("msg", msg);
            map.put("notDelExcelUrl", notDelExcelUrl);

            if (list.size() > 0) {
                String desStr = String.format("成功删除%s个,不成功%s个", list.size(), set.size());
                if(StringUtils.isNotEmpty(notDelExcelUrl)){
                    desStr = String.format("成功删除%s个,不成功%s个, 不成功的下载文件地址:%s", list.size(), set.size(), notDelExcelUrl);
                }
                //添加操作记录
                operationService.add(user, ip, Const.OPERATION_REMOVE, "设备删除", null,
                        "多个刪除", desStr, null, filename, null);
            }
            return Response.successResponse(map);
        }
        return Response.failedResponse("上传文件异常");
    }

    /**
     * 删除处理
     *
     * @param device, operator
     * @time: 2020/9/5 9:19
     * @author: Rock
     * @version 1.0
     */
    private void delHandle(Device device, String operator, SysUser user) {
        //删除通知
        notifyService.deviceReset(device.getId(), operator, true, user);
        //kafka下发消息
        //kafkaService.send(device.getId(), 44);
        //删除用户数据
        accountService.delByQuery(new Query(Criteria.where("imei").is(device.getId())));
        //删除设备数据
        this.delByQuery(new Query(Criteria.where("_id").is(device.getId())));
        canCheckPositionService.delById(device.getId());
        //删除缓存
        redisService.del(device.getId());
        //更新渠道设备导入数
        //channelService.updateNum(device.getAgent());
    }

    public long countByImei(String imei) {
        return this.count(new Query(Criteria.where("_id").is(imei)));
    }
    /**
     * @param agent
     * @time: 2020/9/8 8:44
     * @author: Rock
     * @version 1.0
     */
    public long countByAgent(Long agent) {
        return this.count(new Query(Criteria.where("agent").is(agent)));
    }

    public long countByModelId(String modelId) {
        return this.count(new Query(Criteria.where("model_id").is(modelId)));
    }

    /**
     * 对应设备型号的, 设备激活数量
     */
    public long countActiveNumByModelId(String modelId) {
        return this.count(new Query(Criteria.where("model_id").is(modelId).and("firstLoginTime").exists(true)));
    }

    /**
     * 设备激活数量
     *
     * @param agent
     * @time: 2020/9/8 10:52
     * @author: Rock
     * @version 1.0
     */
    public long countActiveNumByAgent(Long agent) {
        return this.count(new Query(Criteria.where("agent").is(agent).and("firstLoginTime").exists(true)));
    }

    /**
     * @param productionBatch
     * @time: 2020/9/9 14:10
     * @author: Rock
     * @version 1.0
     */
    public long countByProductionBatch(String productionBatch) {
        return this.count(new Query(Criteria.where("production_batch").is(productionBatch)));
    }

    /**
     * @param productionBatch
     * @time: 2020/9/9 14:21
     * @author: Rock
     * @version 1.0
     */
    public long countActiveNumByProductionBatch(String productionBatch) {
        return this.count(new Query(Criteria.where("production_batch").is(productionBatch).and("firstLoginTime").exists(true)));
    }

    /**
     * @param productionBatch
     * @time: 2020/9/9 14:20
     * @author: Rock
     * @version 1.0
     */
    public long countBindNumByProductionBatch(String productionBatch) {
        Query query = new Query(Criteria.where("production_batch").is(productionBatch)
                .andOperator(Criteria.where("u").exists(true), Criteria.where("u").ne(null)));
        return this.count(query);
    }

    /**
     * 调用 设备商店应用监管 获取渠道信息接口 通过HTTP就行
     *
     * @param
     * @time: 2020/10/16 16:53
     * @author: Rock
     * @version 1.0
     */
    public List<WatchStoreChannelVO> getWatchStoreChannel() {
        List<WatchStoreChannelVO> result = new ArrayList<>();
//        String url = watchStoreChannelUrl + "/getway/regulatory/getDistributors?authKey=%s&timestamp=%s";
//        long timestamp = System.currentTimeMillis();
//        String authKey = DigestUtils.md5Hex(Const.MD5_KEY + timestamp).toUpperCase();
//        String res = HttpReq.sendGet(String.format(url, authKey, timestamp), null);
//        log.info("getWatchStoreChannel res: " + res);
//        if (StringUtil.isNotBlank(res)) {
//            JSONObject json = JSON.parseObject(res);
//            if (json != null && new Integer(200).equals(json.getInteger("code"))) {
//                JSONArray jsonArray = json.getJSONArray("disList");
//                if (jsonArray != null) {
//                    for (int i = 0; i < jsonArray.size(); i++) {
//                        WatchStoreChannelVO vo = new WatchStoreChannelVO();
//                        vo.setDisId(jsonArray.getJSONObject(i).getInteger("disId"));
//                        vo.setDisName(jsonArray.getJSONObject(i).getString("disName"));
//                        result.add(vo);
//                    }
//                }
//            }
//        }
        return result;
    }

    /**
     * 查询设备通话时长
     *
     * @param imei
     * @param user
     * @time: 2020/10/29 15:14
     * @author: Rock
     * @version 1.0
     */
    public Response<Object> searchCallDuration(String imei, SysUser user) {
        if (!RegexUtil.validateDeviceId(imei)) {
            return Response.failedResponse("设备号不合法");
        }
        Device device = this.findById(imei);
        if (device == null) {
            return Response.failedResponse("设备号不存在");
        }
        if (user.getType() == Const.CHANNELUSER_TYPE && StringUtil.isNotBlank(device.getAgent())
                && !user.getChannelAff().getChannelCodes().contains(device.getAgent())) {
            return Response.failedResponse("无权限查询该设备");
        }
        if (device.getModules() != null) {
            if (device.getModules().contains(ConstVideo.V0SW)) {
                if (StringUtil.isNotBlank(device.getVideoEndtime())) {
                    return Response.successResponse(String.format("%s的分钟数为%s", imei, device.getVideoEndtime()));
                } else {
                    return Response.successResponse(String.format("%s没有视频通话功能", imei));
                }
            } else if (device.getModules().contains(ConstVideo.V0JF)) {
                if (StringUtil.isNotBlank(device.getOldVideoPermanent())) {
                    if (Const.INT_1.equals(device.getOldVideoPermanent())) {
                        return Response.successResponse(String.format("%s 为免费版", imei));
                    } else {
                        if (StringUtil.isNotBlank(device.getVideoPermanent())) {
                            if (StringUtil.isNotBlank(device.getVideoEndtime())) {
                                if (Const.INT_1.equals(device.getVideoPermanent())) {
                                    return Response.successResponse(String.format("%s 已开通了 永久套餐， 分钟数为：%s", imei, device.getVideoEndtime()));
                                } else {
                                    return Response.successResponse(String.format("%s 没有开通 永久套餐， 分钟数为：%s", imei, device.getVideoEndtime()));
                                }
                            } else {
                                return Response.successResponse(String.format("%s 没有视频通话功能", imei));
                            }
                        } else {
                            return Response.successResponse(String.format("%s 为免费版", imei));
                        }
                    }
                } else {
                    return Response.successResponse(String.format("%s 为免费版", imei));
                }
            } else if (device.getModules().contains(ConstVideo.V0VM)) {
                if (StringUtil.isNotBlank(device.getOldVideoPermanent())) {
                    if (Const.INT_1.equals(device.getOldVideoPermanent())) {
                        return Response.successResponse(String.format("%s 为免费版", imei));
                    } else {
                        if (StringUtil.isNotBlank(device.getVideoPermanent())) {
                            if (StringUtil.isNotBlank(device.getVideoEndtime())) {
                                if (Const.INT_1.equals(device.getVideoPermanent())) {
                                    return Response.successResponse(String.format("%s 已开通了 永久套餐， 分钟数为：%s", imei, device.getVideoEndtime()));
                                } else {
                                    return Response.successResponse(String.format("%s 没有开通 永久套餐， 分钟数为：%s", imei, device.getVideoEndtime()));
                                }
                            } else {
                                return Response.successResponse(String.format("%s 没有视频通话功能", imei));
                            }
                        } else {
                            return Response.successResponse(String.format("%s 为免费版", imei));
                        }
                    }
                } else {
                    return Response.successResponse(String.format("%s 为免费版", imei));
                }
            }
        }
        return Response.successResponse(String.format("%s 设备不支持视频通话", imei));
    }

    /**
     * 取消设备永久套餐
     *
     * @param imei
     * @param user
     * @time: 2020/10/29 15:55
     * @author: Rock
     * @version 1.0
     */
    public Response<Object> resetFree(String imei, SysUser user, String ip) {
        if (!RegexUtil.validateDeviceId(imei)) {
            return Response.failedResponse("设备号不合法");
        }
        Device device = this.findById(imei);
        if (device == null) {
            return Response.failedResponse("设备号不存在");
        }
        if (user.getType() == Const.CHANNELUSER_TYPE && StringUtil.isNotBlank(device.getAgent())
                && !user.getChannelAff().getChannelCodes().contains(device.getAgent())) {
            return Response.failedResponse("无权限操作该设备");
        }
        if (device.getModules() != null) {
            if (device.getModules().contains(ConstVideo.V0JF)) {
                if (StringUtil.isNotBlank(device.getVideoPermanent())) {
                    if (StringUtil.isNotBlank(device.getOldVideoPermanent())) {
                        if (Const.INT_1.equals(device.getOldVideoPermanent())) {
                            return Response.successResponse(String.format("该设备 %s 是免费版，无法取消", imei));
                        }
                    }
                    if (Const.INT_1.equals(device.getVideoPermanent())) {
                        this.updateById(imei, new Update().set("video_permanent", 0));
                        operationService.add(user, ip, "取消永久套餐", "取消",
                                String.format("取消永久套餐设备imei: %s ", imei));
                        return Response.successResponse(String.format(" %s 取消永久套餐成功", imei));
                    }
                } else {
                    return Response.successResponse(String.format("该设备 %s 是免费版，无法取消", imei));
                }
            } else if (device.getModules().contains(ConstVideo.V0VM)) {
                if (StringUtil.isNotBlank(device.getVideoPermanent())) {
                    if (StringUtil.isNotBlank(device.getOldVideoPermanent())) {
                        if (Const.INT_1.equals(device.getOldVideoPermanent())) {
                            return Response.successResponse(String.format("该设备 %s 是免费版，无法取消", imei));
                        }
                    }
                    if (Const.INT_1.equals(device.getVideoPermanent())) {
                        this.updateById(imei, new Update().set("video_permanent", 0));
                        operationService.add(user, ip, "取消永久套餐", "取消",
                                String.format("取消永久套餐设备imei: %s ", imei));
                        return Response.successResponse(String.format(" %s 取消永久套餐成功", imei));
                    }
                } else {
                    return Response.successResponse(String.format("该设备 %s 是免费版，无法取消", imei));
                }
            } else {
                return Response.successResponse(String.format("操作失败，设备号%s不支持该操作", imei));
            }
        }
        return Response.successResponse(String.format("%s 设备不支持视频通话", imei));
    }

    /**
     * @param id
     * @param videoEndtime
     * @time: 2020/10/29 16:58
     * @author: Rock
     * @version 1.0
     */
    private void updateVideoEndtime(String id, Integer videoEndtime, Integer videoPermanent) {
        Update update = new Update();
        if (videoEndtime != null) {
            update.set("video_endtime", videoEndtime);
        }
        if (videoPermanent != null) {
            update.set("video_permanent", videoPermanent);
        }
        this.updateById(id, update);
    }

    /**
     * @param imei
     * @param user
     * @time: 2020/10/29 16:36
     * @author: Rock
     * @version 1.0
     */
    public Response<Object> forceOneReset(String imei, SysUser user, String ip) {
        if (!RegexUtil.validateDeviceId(imei)) {
            return Response.failedResponse("设备号不合法");
        }
        Device device = findById(imei);
        if (device == null) {
            return Response.failedResponse("设备号不存在");
        }
        if (user.getType() == Const.CHANNELUSER_TYPE && StringUtil.isNotBlank(device.getAgent())
                && !user.getChannelAff().getChannelCodes().contains(device.getAgent())) {
            return Response.failedResponse("无权限重置该设备");
        }
        if (device.getModules() != null) {
            if (device.getModules().contains(ConstVideo.V0SW)) {
                updateVideoEndtime(imei, 30, null);
                operationService.add(user, ip, "单个强制重置", "重置",
                        String.format("单个强制重置设备imei: %s ", imei));
                return Response.successResponse(String.format("%s 重置成功", imei));
            } else if (device.getModules().contains(ConstVideo.V0JF)) {
                return Response.successResponse(String.format("%s 设备视频通话为免费", imei));
            } else if (device.getModules().contains(ConstVideo.V0VM)) {
                return Response.successResponse(String.format("%s 设备视频通话为免费", imei));
            }
        }
        return Response.successResponse(String.format("%s 设备不支持视频通话", imei));
    }

    /**
     * @param imei
     * @param user
     * @time: 2020/10/29 16:36
     * @author: Rock
     * @version 1.0
     */
    public Response<Object> oneReset(String imei, SysUser user, String ip) {
        if (!RegexUtil.validateDeviceId(imei)) {
            return Response.failedResponse("设备号不合法");
        }
        Device device = findById(imei);
        if (device == null) {
            return Response.failedResponse("设备号不存在");
        }
        if (user.getType() == Const.CHANNELUSER_TYPE && StringUtil.isNotBlank(device.getAgent())
                && !user.getChannelAff().getChannelCodes().contains(device.getAgent())) {
            return Response.failedResponse("无权限重置该设备");
        }
        if (device.getModules() != null) {
            if (device.getModules().contains(ConstVideo.V0SW)) {
                if (StringUtil.isNotBlank(device.getVideoEndtime())) {
                    if (device.getVideoEndtime() > 30) {
                        return Response.successResponse(String.format("%s 通话时长超过30分钟，如确定重置，请到达【强制重置】", imei));
                    } else {
                        updateVideoEndtime(imei, 30, null);
                        //重置的时候需要重置 设备标记查询位置表(can_check_position)中的数据
                        canCheckPositionService.updateShowMapInfoStr(imei, "");
                        operationService.add(user, ip, "单个重置", "重置",
                                String.format("单个重置设备imei: %s ", imei));
                        return Response.successResponse(String.format("%s 重置成功 ", imei));
                    }
                }
            } else if (device.getModules().contains(ConstVideo.V0JF)) {
                if (StringUtil.isNotBlank(device.getVideoPermanent())) {
                    if (Const.INT_0.equals(device.getVideoPermanent())) {
                        updateVideoEndtime(imei, 30, null);
                        //重置的时候需要重置 设备标记查询位置表(can_check_position)中的数据
                        canCheckPositionService.updateShowMapInfoStr(imei, "");
                        operationService.add(user, ip, "单个重置", "重置",
                                String.format("单个重置设备imei: %s ", imei));
                        return Response.successResponse(String.format("%s 重置成功 ", imei));
                    } else {
                        return Response.successResponse(String.format("该设备%s 是免费版 或者 开通了永久套餐，不需要重置", imei));
                    }
                } else {
                    return Response.successResponse(String.format("%s 为免费版", imei));
                }
            } else if (device.getModules().contains(ConstVideo.V0VM)) {
                if (StringUtil.isNotBlank(device.getVideoPermanent())) {
                    if (Const.INT_0.equals(device.getVideoPermanent())) {
                        updateVideoEndtime(imei, 30, null);
                        //重置的时候需要重置 设备标记查询位置表(can_check_position)中的数据
                        canCheckPositionService.updateShowMapInfoStr(imei, "");
                        operationService.add(user, ip, "单个重置", "重置",
                                String.format("单个重置设备imei: %s ", imei));
                        return Response.successResponse(String.format("%s 重置成功 ", imei));
                    } else {
                        return Response.successResponse(String.format("该设备%s 是免费版 或者 开通了永久套餐，不需要重置", imei));
                    }
                } else {
                    return Response.successResponse(String.format("%s 为免费版", imei));
                }
            }
        }
        return Response.successResponse(String.format("%s 设备不支持视频通话", imei));
    }

    /**
     * 单个转移
     *
     * @param oldImei
     * @param user
     * @time: 2020/10/29 16:36
     * @author: Rock
     * @version 1.0
     */
    public Response<Object> oneShift(String oldImei, String newImei, SysUser user) {
        if (!RegexUtil.validateDeviceId(oldImei)) {
            return Response.failedResponse("旧设备号不合法");
        }
        if (!RegexUtil.validateDeviceId(newImei)) {
            return Response.failedResponse("新设备号不合法");
        }
        if (oldImei.equals(newImei)) {
            return Response.failedResponse("新旧设备imei号不能相同");
        }
        Device oldDevice = findById(oldImei);
        Device newDevice = findById(newImei);
        if (oldDevice == null) {
            return Response.failedResponse("旧设备号不存在");
        }
        if (newDevice == null) {
            return Response.failedResponse("新设备号不存在");
        }
        if (user.getType() == Const.CHANNELUSER_TYPE) {
            if (StringUtil.isNotBlank(oldDevice.getAgent())
                    && !user.getChannelAff().getChannelCodes().contains(oldDevice.getAgent())) {
                return Response.failedResponse(String.format("无权限查询旧设备%s", oldImei));
            }
            if (StringUtil.isNotBlank(newDevice.getAgent())
                    && !user.getChannelAff().getChannelCodes().contains(newDevice.getAgent())) {
                return Response.failedResponse(String.format("无权限查询新设备%s", newImei));
            }
        }
        if (oldDevice.getModules() == null) {
            return Response.successResponse(String.format("%s 设备不支持视频通话", oldImei));
        } else if (newDevice.getModules() == null) {
            return Response.successResponse(String.format("%s 设备不支持视频通话", newImei));
        } else {
            if (oldDevice.getModules().contains(ConstVideo.V0SW) && newDevice.getModules().contains(ConstVideo.V0SW)) {
                //转移处理
                return shiftHandle(user.getAccount(), oldDevice, newDevice, 0);
            } else if (oldDevice.getModules().contains(ConstVideo.V0JF) && newDevice.getModules().contains(ConstVideo.V0JF)) {
                if (oldDevice.getOldVideoPermanent() != null && newDevice.getOldVideoPermanent() != null
                        && oldDevice.getOldVideoPermanent().equals(newDevice.getOldVideoPermanent())) {
                    if (oldDevice.getOldVideoPermanent() == 0) {
                        if (oldDevice.getVideoPermanent() != null) {
                            if (oldDevice.getVideoPermanent() == 1) {
                                //转移处理
                                return shiftHandle(user.getAccount(), oldDevice, newDevice, 1);
                            } else {
                                //转移处理
                                return shiftHandle(user.getAccount(), oldDevice, newDevice, 2);
                            }
                        } else {
                            return Response.successResponse(String.format("%s 设备不支持视频通话", oldImei));
                        }
                    } else {
                        return Response.successResponse("两个设备都是免费版，无法转移");
                    }
                } else {
                    return Response.successResponse("两个设备的视频套餐不一致，无法转移");
                }
            } else if (oldDevice.getModules().contains(ConstVideo.V0VM) && newDevice.getModules().contains(ConstVideo.V0VM)) {
                if (oldDevice.getOldVideoPermanent() != null && newDevice.getOldVideoPermanent() != null
                        && oldDevice.getOldVideoPermanent().equals(newDevice.getOldVideoPermanent())) {
                    if (oldDevice.getOldVideoPermanent() == 0) {
                        if (oldDevice.getVideoPermanent() != null) {
                            if (oldDevice.getVideoPermanent() == 1) {
                                //转移处理
                                return shiftHandle(user.getAccount(), oldDevice, newDevice, 1);
                            } else {
                                //转移处理
                                return shiftHandle(user.getAccount(), oldDevice, newDevice, 2);
                            }
                        } else {
                            return Response.successResponse(String.format("%s 设备不支持视频通话", oldImei));
                        }
                    } else {
                        return Response.successResponse("两个设备都是免费版，无法转移");
                    }
                } else {
                    return Response.successResponse("两个设备的视频套餐不一致，无法转移");
                }
            } else {
                return Response.successResponse("视频通话类型不一致");
            }
        }
    }

    /**
     * 转移处理
     *
     * @param username
     * @param oldDevice
     * @param newDevice
     * @param flag
     * @time: 2020/10/30 9:18
     * @author: Rock
     * @version 1.0
     */
    private Response<Object> shiftHandle(String username, Device oldDevice, Device newDevice, int flag) {
        if (oldDevice.getVideoEndtime() == null) {
            return Response.successResponse(String.format("设备%s不支持视频通话", oldDevice.getId()));
        }
        if (newDevice.getVideoEndtime() == null) {
            return Response.successResponse(String.format("设备%s不支持视频通话", newDevice.getId()));
        }
        if (flag == 1) {
            updateVideoEndtime(newDevice.getId(), oldDevice.getVideoEndtime(), 1);
            updateVideoEndtime(oldDevice.getId(), 30, 0);
            shiftService.save(username, oldDevice.getId(), newDevice.getVideoEndtime(), 0,
                    newDevice.getId(), oldDevice.getVideoEndtime(), 1, oldDevice.getVideoEndtime());
            return Response.successResponse(String.format("转移后设备%s 已开通永久套餐", newDevice.getId()));
        } else if (flag == 2) {
            updateVideoEndtime(newDevice.getId(), oldDevice.getVideoEndtime(), null);
            updateVideoEndtime(oldDevice.getId(), 30, null);
            shiftService.save(username, oldDevice.getId(), newDevice.getVideoEndtime(), null,
                    newDevice.getId(), oldDevice.getVideoEndtime(), null, oldDevice.getVideoEndtime());
            return Response.successResponse(String.format("转移后设备%s 剩余时长为%s 分钟", newDevice.getId(), oldDevice.getVideoEndtime()));
        } else {
            int videoEndTime = newDevice.getVideoEndtime() + oldDevice.getVideoEndtime() - 30;
            updateVideoEndtime(newDevice.getId(), videoEndTime, null);
            updateVideoEndtime(oldDevice.getId(), 30, null);
            shiftService.save(username, oldDevice.getId(), oldDevice.getVideoEndtime(), null,
                    newDevice.getId(), newDevice.getVideoEndtime(), null, videoEndTime);
            return Response.successResponse(String.format("设备%s 原时长为%s 分钟，转移后为%s分钟", newDevice.getId(), newDevice.getVideoEndtime(), videoEndTime));
        }
    }

    /**
     * @param videoModelId
     * @time: 2020/11/5 17:03
     * @author: Rock
     * @version 1.0
     */
    public long countImportNumByVideoModelId(String videoModelId) {
        return this.count(new Query(Criteria.where("videoModelId").is(videoModelId)));
    }


    /**
     * @description 更新设备型号
     * @author cwj
     * @param [model, moudles, oldModel]
     * @return void
     * @date @time 2024/10/29 14:32
     **/
    public void updateDeviceModels(String model,String modules,String id) {
        Query query = new Query(Criteria.where("model_id").is(id));
        boolean isExists= mongoTemplate.exists(query,getTClass());
        //减少不必要的更新操作
        if(isExists){
            Update update = new Update();
            update.set("model",model);
            update.set("modules",modules);
            UpdateResult result = mongoTemplate.updateMulti(query, update, getTClass());
            log.info("更新设备数据的结果：{}",result);
        }
    }

    /**
     * @description 检查有无设备仍然使用该模型
     * @author cwj
     * @param [modelId]
     * @return boolean
     * @date @time 2024/11/2 14:10
     **/
    public boolean checkDeviceExistsByModleId(String modelId){
        Query query = new Query(Criteria.where("model_id").is(modelId));
        return mongoTemplate.exists(query,getTClass());
    }

    /**
     * @param [changeAddress]
     * @return com.iot08.common.response.Response<java.lang.Object>
     * @description 切换设备推送地址
     * @author cwj
     * @date @time 2025/2/28 12:11
     **/
    public Response<Object> changeAddress(ChangeAddress changeAddress) throws IOException {
        Device device = this.findById(changeAddress.getImei());
        if(ObjectUtils.isEmpty(device)){
            return Response.failedResponse("切换设备"+changeAddress.getImei()+"不存在！");
        }
        changeAddress.setToken("px123456");
        JSONObject parmas = new JSONObject();
        parmas.put("token", changeAddress.getToken());
        parmas.put("imei", changeAddress.getImei());
        parmas.put("ip", changeAddress.getIp());
        parmas.put("port", changeAddress.getPort());
        String resJSONStr = HttpReq.sendPostJson(tcpUrl, parmas.toJSONString());
        log.info("返回数据内容为：{}",resJSONStr);
        if(StringUtils.isNotEmpty(resJSONStr)){
            return JSONObject.parseObject(resJSONStr,Response.class);
        } else {
            return Response.failedResponse("切换设备"+changeAddress.getImei()+"推送数据地址失败");
        }
    }
}
